﻿using BLToolkit.Data.Linq;
using CommonHelper;
using CommonLibrary;
using CommonLibrary.Interface;
using CommonLibrary.Models;
using CommonLibrary.WorkFlow;
using CommonSite.Common;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.Mvc;

namespace CommonSite.Controllers
{
    [UserAuthorizeAttribute]
    public class ItemController : Controller
    {
        public ActionResult Index()
        {
            using (CommonDatabase db = new CommonDatabase())
            {
                int user = UserAction.GetCurrentUser().UserId;
                // 查询可以使用的审批流程                
                var cmd =
@"select id as ""Id"", name as ""Name"" from wf_workflow where id in 
(
    select distinct flowid from wf_flowrole where roleid in (
        select roleid from sys_userrole where userid = @user
    )
);";
                var dt = db.SetCommand(cmd, db.Parameter("@user", user))
                           .ExecuteDataTable();

                ViewBag.Total = dt.Rows.Count;
                ViewBag.Rows = JSON.ToString(dt);
            }

            return View();
        }

        [HttpGet]
        public ActionResult CreateItem(int id)
        {
            try
            {
                ControllerHelper.SetBackUrl(this);

                using (var db = new CommonDatabase())
                {
                    var flow = db.wf_Workflow.Where(k => k.Id == id).First();
                    var form = db.wf_FormInstance.Where(k => k.Id == flow.FormInstanceId).First();
                    var fields = db.wf_FieldInstance.Where(k => k.FormId == flow.FormInstanceId).ToList();

                    ViewBag.Flow = flow;
                    ViewBag.Form = form;
                    ViewBag.Fields = fields;
                }
            }
            catch
            {
                return RedirectToAction("Index");
            }

            return View();
        }

        [HttpPost]
        public ActionResult CreateItem(int id, string dept)
        {
            try
            {
                int deptId = CryptHelper.DecryptToInt32(dept);
                using (var db = new CommonDatabase(CommonOption.ReadWrite))
                {
                    db.BeginTransaction();

                    var user = UserAction.GetCurrentUser().UserId;
                    var flow = db.wf_Workflow.Where(k => k.Id == id).First();
                    var form = db.wf_FormInstance.Where(k => k.Id == flow.FormInstanceId).First();
                    var fields = db.wf_FieldInstance.Where(k => k.FormId == flow.FormInstanceId).ToList();

                    // 表单数据ID
                    int dataId;

                    #region 将表单数据添加到数据表中
                    var table = new SqlName("form_" + form.Id, owner: "workflow");
                    var columns = (from p in fields
                                   select new
                                   {
                                       Name = new SqlName("field_" + p.Id),
                                       Value = this.Request.Form["field_" + p.Id],
                                       Field = p
                                   }).ToList();
                    var builder = new SampleSqlBuilder();

                    builder.InsertInto(
                        table,
                        columns.Select(k => k.Name).ToArray());

                    // 添加表单参数
                    foreach (var c in columns)
                    {
                        switch (c.Field.ControlId)
                        {
                            case 8:
                                builder.Values(new SqlValue(db.Parameter("@" + c.Name, c.Field.Argument)));
                                break;

                            case 10:
                                builder.Values(new SqlValue(db.Parameter("@" + c.Name, 1)));
                                break;

                            case 11:
                                // 文件上传控件
                                var file = this.Request.Files[c.Name.Name];
                                if (file.ContentLength != 0)
                                {
                                    var crc = Crc32.GetStreamCRC32(file.InputStream);
                                    var ext = System.IO.Path.GetExtension(file.FileName);
                                    var dir = Server.MapPath("~/Upload");
                                    var filepath = System.IO.Path.Combine(dir, crc + ext);
                                    if (!System.IO.File.Exists(filepath))
                                    {
                                        file.SaveAs(filepath);
                                    }

                                    builder.Values(new SqlValue(db.Parameter("@" + c.Name, "/Upload/" + crc + ext)));
                                }
                                else
                                {
                                    builder.Values(new SqlValue(db.Parameter("@" + c.Name, null)));
                                }

                                break;

                            default:
                                builder.Values(new SqlValue(db.Parameter("@" + c.Name, c.Value)));
                                break;
                        }
                    }

                    builder.AppendQuery(" returning Id");
                    builder.End();

                    dataId = db.SetCommand(builder.ToString(), builder.Parameters)
                                 .ExecuteScalar<int>();

                    foreach (var c in columns)
                    {
                        if (c.Field.ControlId == 10)
                        {
                            InsertTableData(db, c.Field, dataId, c.Value);
                        }
                    }
                    #endregion

                    #region 启动审批流程

                    //ApprovalWorkFlow approval = new ApprovalWorkFlow(db);
                    //approval.Start(flow, form, objectId, user, deptId);

                    WorkFlowManager manager = new WorkFlowManager(db);
                    manager.Start(flow, dataId, user, deptId);

                    #endregion

                    db.CommitTransaction();
                }

                return Content(TemplateHelper.AlertAndRedirect("提交成功", "/Item"));
            }
            catch (Exception ex)
            {
                return Content(TemplateHelper.AlertAndRedirect("提交失败， 原因: " + ex.Message, "/Item"));
            }
        }

        public ActionResult Histories(DateTime? start, DateTime? end)
        {
            using (CommonDatabase db = new CommonDatabase())
            {
                int user = UserAction.GetCurrentUser().UserId;
                if (start == null) start = DateTime.Now.AddMonths(-1);
                if (end == null) end = DateTime.Now;
                end = end.Value.AddDays(1);

                // 查询正在进行中的流程实例
                string cmd =
@"select t1.id,
         to_char(t1.creationtime, 'yyyy 年 MM 月 dd 日') as creationtime,
         to_char(t1.updatedtime, 'yyyy 年 MM 月 dd 日') as updatedtime,
         t1.state,
         t1.flowname
from view_flowobject t1 
where 
    t1.createuserid = @user and
    t1.creationtime >= @start and
    t1.creationtime < @end
order by t1.id desc;";

                var dt = db.SetCommand(
                                cmd,
                                db.Parameter("@user", user),
                                db.Parameter("@start", start),
                                db.Parameter("@end", end))
                           .ExecuteDataTable();

                ViewBag.Total = dt.Rows.Count;
                ViewBag.Rows = JSON.ToString(dt);
            }

            return View();
        }

        public ActionResult Info(int id)
        {
            try
            {
                ControllerHelper.SetBackUrl(this);

                using (var db = new CommonDatabase())
                {
                    var user = UserAction.GetCurrentUser().UserId;
                    var cmd = @"select * from view_flowobject where id = @id;";
                    var flowObject = db.SetCommand(cmd, db.Parameter("@id", id))
                                 .ExecuteDataTable().Rows[0];
                    var form = db.wf_FormInstance.Where(k => k.Id == (int)flowObject["forminstanceid"]).First();
                    var fields = db.wf_FieldInstance.Where(k => k.FormId == (int)flowObject["forminstanceid"]).ToList();
                    var row = db.SetCommand(
                                    string.Format("select * from workflow.form_{0} where Id = @id", form.Id),
                                    db.Parameter("@id", (int)flowObject["dataid"]))
                                .ExecuteDataTable().Rows[0];

                    ViewBag.FlowId = id;
                    ViewBag.Flow = flowObject;
                    ViewBag.Form = form;
                    ViewBag.Fields = fields;
                    ViewBag.Row = row;
                    ViewBag.CanCancel = user == (int)flowObject["createuserid"] && (int)flowObject["State"] == 1;
                }

                return View();
            }
            catch
            {
                return RedirectToAction("Histories");
            }
        }

        public ActionResult WorkUsers(int id)
        {
            using (var db = new CommonDatabase())
            {
                var cmd = "select * from view_workuser where flowobjectid = @id";
                var dt = db.SetCommand(cmd, db.Parameter("@id", id))
                           .ExecuteDataTable();

                return Content(JSON.ToString(new
                {
                    Total = dt.Rows.Count,
                    Rows = dt
                }));
            }
        }

        public ActionResult Cancel(int flowid)
        {
            try
            {
                using (CommonDatabase db = new CommonDatabase(CommonOption.ReadWrite))
                {
                    db.BeginTransaction();
                    var cmd = "select count(*) from wf_flowobject where id = @id and state = 1;";
                    if (db.SetCommand(cmd, db.Parameter("@id", flowid)).ExecuteScalar<int>() == 0)
                        return RedirectToAction("Histories");

                    cmd = "update wf_flowobject set state = 0, updatedtime = now() where id = @id;";
                    db.SetCommand(cmd, db.Parameter("@id", flowid)).ExecuteNonQuery();

                    cmd =
@"update wf_taskobject set state = 0, result = '提交人撤销申请', updatedtime = now()
where flowobjectid = @id and state = 1;";
                    db.SetCommand(cmd, db.Parameter("@id", flowid)).ExecuteNonQuery();

                    db.CommitTransaction();
                }
            }
            catch
            {
            }

            return RedirectToAction("Histories");
        }

        private static int InsertTableData(CommonDatabase db, wf_FieldInstance field, int owner, string json)
        {
            var values = ((object[])JSON.Parse(json)).Cast<Hashtable>().ToList();
            var table = new SqlName("field_" + field.Id, owner: "workflow");
            var columns = (from p in db.wf_Column
                           where p.TableId == field.Source && p.State == 1
                           select new SqlName("column_" + p.Id, null, null)).ToArray();
            var builder = new SampleSqlBuilder();

            // insert into workflow.field_{0}(...) values(...); 
            builder.InsertInto(table, new SqlName("owner"));
            builder.InsertInto(table, columns);

            builder.Values(new SqlValue(db.Parameter("@owner", owner)));
            builder.Values(columns.Select(k => new SqlValue(db.Parameter("@" + k.Name, null))).ToArray());

            builder.End();

            var cmd = builder.ToString();
            var parameters = builder.Parameters;
            foreach (var item in values)
            {
                foreach (var p in parameters)
                {
                    if (p.ParameterName != "@owner")
                    {
                        p.Value = item[p.ParameterName.Substring(1)];
                    }
                }

                db.SetCommand(cmd, parameters)
                  .ExecuteNonQuery();
            }

            return 0;
        }
    }
}
